package aor2.memory;

import javax.swing.JOptionPane;
import aor2.components.Restorable;
import aor2.systembus.SystemBus;

public class Memory extends Thread implements Restorable {
	// TODO ovo je samo za testiranje, treba uraditi ceo ovaj paket
	protected long[] word;
	private boolean isActive = false;
	private SystemBus buses = SystemBus.getInstance();
	private static final int time = 5;
	private static final int timeback = 2;

	public Memory(int capacity) {
		super();
		word = new long[capacity];
		this.isActive = true;
		this.start();
	}

	public void run() {

		while (isActive) {
			synchronized (buses.getSync()) {
				try {
					buses.getSync().wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			if (buses.getRdbus()) {
				buses.setFcbus(false);
				buses.setDatabusHigh();//mozda ne treba ovde
				
				try {
					Thread.sleep((long) (Math.random() * time));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				buses.setDatabus(readWord((int) buses.getAddressbusState()));
				buses.setFcbus(true);
 				try {
					Thread.sleep((long) (Math.random() * timeback));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				synchronized (buses.getSyncDone()) {
					try {
						if (!buses.getSyncFlag()) {
							buses.getSyncDone().wait();							
						}
						else buses.setSyncFlag(false);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				buses.setDatabusHigh();
				buses.setFcbus(false);
				try {
					Thread.sleep((long) (Math.random() * time));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				buses.setFcbusHigh();

			} 
			else if (buses.getWrbus()) {
				buses.setFcbus(false);
				writeWord((int) buses.getAddressbusState(),
						buses.getDatabusState());
				try {
					Thread.sleep((long) (Math.random() * (time + timeback)));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				buses.setFcbus(true);
				try {
					Thread.sleep((long) (Math.random() * timeback));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				synchronized (buses.getSyncDone()) {
					try {
						if (!buses.getSyncFlag()) {
							buses.getSyncDone().wait();							
						}
						else buses.setSyncFlag(false);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				buses.setFcbus(false);
				try {
					Thread.sleep((long) (Math.random() * time));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				buses.setFcbusHigh();
				}
		}
	}

	public void stopMem() {
		this.isActive = false;
		this.interrupt();
	}

	public long readWord(int memadr) {
		if (memadr < 0 || memadr >= capacity()) {
			JOptionPane.showMessageDialog(null,
					"ADRESA NE POSTOJI U MEMORIJI!!!");
			System.exit(1);
		}
		return word[memadr];
	}

	public int capacity() {
		return word.length;
	}

	public void writeWord(int memadr, long word) {
		// FIXME
		if (memadr < 0 || memadr >= capacity()) {
			JOptionPane.showMessageDialog(null,
					"ADRESA NE POSTOJI U MEMORIJI!!!");
			System.exit(1);
		}
		this.word[memadr] = word;
	}

	public void restore(String restorePoint) {
		String trim = restorePoint.replace(beginTag(), "");
		trim = trim.replace(endTag(), "");
		trim = trim.trim();
		String[] states = trim.split("\\s");
		for (int i = 0; i < states.length; i++)
			word[i] = Long.parseLong(states[i], 16);
	}

	public String createRestorePoint() {
		String res = beginTag() + "\n";// XXX izbacen \t da bi sve bilo
										// alignovano
		for (int i = 0; i < capacity(); i++) {
			res += Long.toHexString(word[i]);
			if (i % 8 == 7)
				res += "\n";
			else
				res += " ";
		}
		res += "\n" + endTag();
		return res;
	}

	public String beginTag() {
		return "<Memory>";
	}

	public String endTag() {
		return "</Memory>";
	}

	public static void main(String[] args) {
		Memory mem = new Memory(20);
		for (int i = 0; i < 20; i++)
			mem.writeWord(i, 4 * i);
		String restString = mem.createRestorePoint();

		System.out.println(restString);

		String preString = restString;
		restString = mem.createRestorePoint();

		System.out.println(restString);

		mem.restore(preString);
		restString = mem.createRestorePoint();

		System.out.println(restString);
	}

}
